package service

import (
	"context"
	"fmt"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"

	"goldtree/internal/dao"
	"goldtree/internal/entity"
)

// TagService 标签服务
type TagService struct{}

var Tag = TagService{}

// CreateTagReq 创建标签请求
type CreateTagReq struct {
	Name        string `json:"name" v:"required|length:1,50#标签名称不能为空|标签名称长度不能超过50位"`
	Category    string `json:"category" v:"required|length:1,30#标签分类不能为空|标签分类长度不能超过30位"`
	ParentId    *int   `json:"parent_id"`
	Color       string `json:"color" v:"length:7#颜色代码长度必须为7位"`
	Description string `json:"description"`
	SortOrder   int    `json:"sort_order" v:"min:0#排序必须大于等于0"`
}

// UpdateTagReq 更新标签请求
type UpdateTagReq struct {
	Id          int    `json:"id" v:"required|min:1#ID不能为空|ID必须大于0"`
	Name        string `json:"name" v:"required|length:1,50#标签名称不能为空|标签名称长度不能超过50位"`
	Category    string `json:"category" v:"required|length:1,30#标签分类不能为空|标签分类长度不能超过30位"`
	ParentId    *int   `json:"parent_id"`
	Color       string `json:"color" v:"length:7#颜色代码长度必须为7位"`
	Description string `json:"description"`
	SortOrder   int    `json:"sort_order" v:"min:0#排序必须大于等于0"`
	IsActive    *bool  `json:"is_active"`
}

// GetTagListReq 获取标签列表请求
type GetTagListReq struct {
	Page     int    `json:"page" v:"min:1#页码必须大于0"`
	Limit    int    `json:"limit" v:"min:1|max:100#每页数量必须大于0|每页数量不能超过100"`
	Keyword  string `json:"keyword"`
	Category string `json:"category"`
	ParentId *int   `json:"parent_id"`
	IsActive *bool  `json:"is_active"`
}

// TagListRes 标签列表响应
type TagListRes struct {
	List  []*entity.Tag `json:"list"`
	Total int           `json:"total"`
	Page  int           `json:"page"`
	Limit int           `json:"limit"`
}

// AssignTagReq 分配标签请求
type AssignTagReq struct {
	StockCode  string  `json:"stock_code" v:"required|length:6,10#股票代码不能为空|股票代码长度为6-10位"`
	TagId      int     `json:"tag_id" v:"required|min:1#标签ID不能为空|标签ID必须大于0"`
	Weight     float64 `json:"weight" v:"min:0|max:1#权重必须在0-1之间"`
	AssignedBy string  `json:"assigned_by"`
}

// BatchAssignTagReq 批量分配标签请求
type BatchAssignTagReq struct {
	StockCodes []string `json:"stock_codes" v:"required#股票代码列表不能为空"`
	TagId      int      `json:"tag_id" v:"required|min:1#标签ID不能为空|标签ID必须大于0"`
	Weight     float64  `json:"weight" v:"min:0|max:1#权重必须在0-1之间"`
	AssignedBy string   `json:"assigned_by"`
}

// TagDetailRes 标签详情响应
type TagDetailRes struct {
	Tag         *entity.Tag     `json:"tag"`
	StockCount  int             `json:"stock_count"`
	ChildTags   []*entity.Tag   `json:"child_tags"`
	StockList   []interface{}   `json:"stock_list"` // 关联的股票列表
	TagStats    *TagStats       `json:"tag_stats"`
}

// TagStats 标签统计信息
type TagStats struct {
	StockCount     int     `json:"stock_count"`     // 关联股票数量
	ChildTagCount  int     `json:"child_tag_count"` // 子标签数量
	TotalWeight    float64 `json:"total_weight"`    // 总权重
	AverageWeight  float64 `json:"average_weight"`  // 平均权重
}

// TagTreeNode 标签树节点
type TagTreeNode struct {
	*entity.Tag
	Children []*TagTreeNode `json:"children"`
}

// Create 创建标签
func (s *TagService) Create(ctx context.Context, req *CreateTagReq) (*entity.Tag, error) {
	// 验证标签名称是否已存在
	exists, err := dao.Tag.IsNameExists(ctx, req.Name)
	if err != nil {
		return nil, gerror.Wrap(err, "检查标签名称失败")
	}
	if exists {
		return nil, gerror.New("标签名称已存在")
	}

	// 如果有父标签，验证父标签是否存在
	if req.ParentId != nil && *req.ParentId > 0 {
		parentTag, err := dao.Tag.GetById(ctx, *req.ParentId)
		if err != nil {
			return nil, gerror.Wrap(err, "获取父标签信息失败")
		}
		if parentTag == nil {
			return nil, gerror.New("父标签不存在")
		}
	}

	// 构建标签实体
	tag := &entity.Tag{
		Name:        req.Name,
		Category:    req.Category,
		ParentId:    req.ParentId,
		Color:       req.Color,
		Description: req.Description,
		SortOrder:   req.SortOrder,
		IsActive:    true,
	}

	// 插入数据库
	id, err := dao.Tag.Insert(ctx, tag)
	if err != nil {
		return nil, gerror.Wrap(err, "创建标签失败")
	}

	// 返回创建的标签信息
	tag.Id = int(id)
	g.Log().Info(ctx, "创建标签成功", "id", id, "name", req.Name, "category", req.Category)
	return tag, nil
}

// Update 更新标签
func (s *TagService) Update(ctx context.Context, req *UpdateTagReq) error {
	// 检查标签是否存在
	existingTag, err := dao.Tag.GetById(ctx, req.Id)
	if err != nil {
		return gerror.Wrap(err, "获取标签信息失败")
	}
	if existingTag == nil {
		return gerror.New("标签不存在")
	}

	// 检查名称是否与其他标签冲突
	if existingTag.Name != req.Name {
		exists, err := dao.Tag.IsNameExists(ctx, req.Name)
		if err != nil {
			return gerror.Wrap(err, "检查标签名称失败")
		}
		if exists {
			return gerror.New("标签名称已存在")
		}
	}

	// 如果有父标签，验证父标签是否存在
	if req.ParentId != nil && *req.ParentId > 0 {
		// 不能将自己设为父标签
		if *req.ParentId == req.Id {
			return gerror.New("不能将自己设为父标签")
		}
		
		parentTag, err := dao.Tag.GetById(ctx, *req.ParentId)
		if err != nil {
			return gerror.Wrap(err, "获取父标签信息失败")
		}
		if parentTag == nil {
			return gerror.New("父标签不存在")
		}
	}

	// 构建更新数据
	updateData := &entity.Tag{
		Name:        req.Name,
		Category:    req.Category,
		ParentId:    req.ParentId,
		Color:       req.Color,
		Description: req.Description,
		SortOrder:   req.SortOrder,
	}

	if req.IsActive != nil {
		updateData.IsActive = *req.IsActive
	}

	// 更新数据库
	err = dao.Tag.Update(ctx, req.Id, updateData)
	if err != nil {
		return gerror.Wrap(err, "更新标签失败")
	}

	g.Log().Info(ctx, "更新标签成功", "id", req.Id, "name", req.Name)
	return nil
}

// Delete 删除标签
func (s *TagService) Delete(ctx context.Context, id int) error {
	// 检查标签是否存在
	tag, err := dao.Tag.GetById(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "获取标签信息失败")
	}
	if tag == nil {
		return gerror.New("标签不存在")
	}

	// 检查是否有子标签
	childTags, err := dao.Tag.GetChildTags(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "检查子标签失败")
	}
	if len(childTags) > 0 {
		return gerror.New("存在子标签，不能删除")
	}

	// 删除标签（包括股票关联）
	err = dao.Tag.Delete(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "删除标签失败")
	}

	g.Log().Info(ctx, "删除标签成功", "id", id, "name", tag.Name)
	return nil
}

// GetById 根据ID获取标签
func (s *TagService) GetById(ctx context.Context, id int) (*entity.Tag, error) {
	tag, err := dao.Tag.GetById(ctx, id)
	if err != nil {
		return nil, gerror.Wrap(err, "获取标签信息失败")
	}
	return tag, nil
}

// GetDetail 获取标签详情
func (s *TagService) GetDetail(ctx context.Context, id int) (*TagDetailRes, error) {
	// 获取标签基本信息
	tag, err := dao.Tag.GetById(ctx, id)
	if err != nil {
		return nil, gerror.Wrap(err, "获取标签信息失败")
	}
	if tag == nil {
		return nil, gerror.New("标签不存在")
	}

	// 获取子标签
	childTags, err := dao.Tag.GetChildTags(ctx, id)
	if err != nil {
		g.Log().Warning(ctx, "获取子标签失败", "id", id, "error", err)
		childTags = []*entity.Tag{}
	}

	// 获取关联的股票数量
	stockCount, err := dao.StockTag.GetCountByTagId(ctx, id)
	if err != nil {
		g.Log().Warning(ctx, "获取关联股票数量失败", "id", id, "error", err)
		stockCount = 0
	}

	// 获取关联的股票列表
	stockListMap, err := dao.StockTag.GetStocksByTag(ctx, id, 1, 10) // 只显示前10个
	if err != nil {
		g.Log().Warning(ctx, "获取关联股票列表失败", "id", id, "error", err)
		stockListMap = []map[string]interface{}{}
	}
	
	// 将 []map[string]interface{} 转换为 []interface{}
	stockList := make([]interface{}, len(stockListMap))
	for i, stock := range stockListMap {
		stockList[i] = stock
	}

	// 计算统计信息
	stats := &TagStats{
		StockCount:    stockCount,
		ChildTagCount: len(childTags),
	}

	return &TagDetailRes{
		Tag:        tag,
		StockCount: stockCount,
		ChildTags:  childTags,
		StockList:  stockList,
		TagStats:   stats,
	}, nil
}

// GetList 获取标签列表
func (s *TagService) GetList(ctx context.Context, req *GetTagListReq) (*TagListRes, error) {
	// 设置默认值
	if req.Page == 0 {
		req.Page = 1
	}
	if req.Limit == 0 {
		req.Limit = 20
	}

	// 构建查询条件
	var conditions []interface{}
	if req.Keyword != "" {
		conditions = append(conditions, "(name LIKE ? OR description LIKE ?)", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.Category != "" {
		condition := "category = ?"
		if len(conditions) > 0 {
			conditions[0] = fmt.Sprintf("%s AND %s", conditions[0], condition)
			conditions = append(conditions, req.Category)
		} else {
			conditions = append(conditions, condition, req.Category)
		}
	}
	if req.ParentId != nil {
		condition := "parent_id = ?"
		if len(conditions) > 0 {
			conditions[0] = fmt.Sprintf("%s AND %s", conditions[0], condition)
			conditions = append(conditions, *req.ParentId)
		} else {
			conditions = append(conditions, condition, *req.ParentId)
		}
	}
	if req.IsActive != nil {
		condition := "is_active = ?"
		if len(conditions) > 0 {
			conditions[0] = fmt.Sprintf("%s AND %s", conditions[0], condition)
			conditions = append(conditions, *req.IsActive)
		} else {
			conditions = append(conditions, condition, *req.IsActive)
		}
	}

	// 获取列表
	tags, err := dao.Tag.GetList(ctx, req.Page, req.Limit, conditions...)
	if err != nil {
		return nil, gerror.Wrap(err, "获取标签列表失败")
	}

	// 获取总数
	total, err := dao.Tag.GetCount(ctx, conditions...)
	if err != nil {
		return nil, gerror.Wrap(err, "获取标签总数失败")
	}

	return &TagListRes{
		List:  tags,
		Total: total,
		Page:  req.Page,
		Limit: req.Limit,
	}, nil
}

// GetActiveTags 获取激活的标签列表
func (s *TagService) GetActiveTags(ctx context.Context) ([]*entity.Tag, error) {
	tags, err := dao.Tag.GetActiveTags(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取激活标签列表失败")
	}
	return tags, nil
}

// GetByCategory 根据分类获取标签列表
func (s *TagService) GetByCategory(ctx context.Context, category string) ([]*entity.Tag, error) {
	tags, err := dao.Tag.GetByCategory(ctx, category)
	if err != nil {
		return nil, gerror.Wrap(err, "获取分类标签列表失败")
	}
	return tags, nil
}

// GetCategoryList 获取标签分类列表
func (s *TagService) GetCategoryList(ctx context.Context) ([]string, error) {
	categories, err := dao.Tag.GetCategoryList(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取标签分类列表失败")
	}
	return categories, nil
}

// GetTagTree 获取标签树结构
func (s *TagService) GetTagTree(ctx context.Context) ([]*TagTreeNode, error) {
	// 获取根标签
	rootTags, err := dao.Tag.GetRootTags(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取根标签失败")
	}

	var tree []*TagTreeNode
	for _, rootTag := range rootTags {
		node := &TagTreeNode{Tag: rootTag}
		// 递归获取子标签
		children, err := s.buildTagTree(ctx, rootTag.Id)
		if err != nil {
			g.Log().Warning(ctx, "构建标签树失败", "tag_id", rootTag.Id, "error", err)
		} else {
			node.Children = children
		}
		tree = append(tree, node)
	}

	return tree, nil
}

// AssignTag 分配标签给股票
func (s *TagService) AssignTag(ctx context.Context, req *AssignTagReq) error {
	// 检查股票是否存在
	stock, err := dao.Stock.GetByCode(ctx, req.StockCode)
	if err != nil {
		return gerror.Wrap(err, "获取股票信息失败")
	}
	if stock == nil {
		return gerror.New("股票不存在")
	}

	// 检查标签是否存在
	tag, err := dao.Tag.GetById(ctx, req.TagId)
	if err != nil {
		return gerror.Wrap(err, "获取标签信息失败")
	}
	if tag == nil {
		return gerror.New("标签不存在")
	}

	// 检查是否已经关联
	exists, err := dao.StockTag.IsRelationExists(ctx, req.StockCode, req.TagId)
	if err != nil {
		return gerror.Wrap(err, "检查股票标签关联失败")
	}
	if exists {
		return gerror.New("股票已关联该标签")
	}

	// 创建关联
	stockTag := &entity.StockTag{
		StockCode:  req.StockCode,
		TagId:      req.TagId,
		Weight:     req.Weight,
		AssignedAt: gtime.Now(),
		AssignedBy: req.AssignedBy,
	}

	_, err = dao.StockTag.Insert(ctx, stockTag)
	if err != nil {
		return gerror.Wrap(err, "分配标签失败")
	}

	g.Log().Info(ctx, "分配标签成功", "stock_code", req.StockCode, "tag_id", req.TagId)
	return nil
}

// BatchAssignTag 批量分配标签给股票
func (s *TagService) BatchAssignTag(ctx context.Context, req *BatchAssignTagReq) error {
	// 检查标签是否存在
	tag, err := dao.Tag.GetById(ctx, req.TagId)
	if err != nil {
		return gerror.Wrap(err, "获取标签信息失败")
	}
	if tag == nil {
		return gerror.New("标签不存在")
	}

	// 验证股票代码并构建关联列表
	var stockTags []*entity.StockTag
	for _, stockCode := range req.StockCodes {
		// 检查股票是否存在
		stock, err := dao.Stock.GetByCode(ctx, stockCode)
		if err != nil {
			return gerror.Wrapf(err, "获取股票信息失败: %s", stockCode)
		}
		if stock == nil {
			return gerror.Newf("股票不存在: %s", stockCode)
		}

		// 检查是否已经关联
		exists, err := dao.StockTag.IsRelationExists(ctx, stockCode, req.TagId)
		if err != nil {
			return gerror.Wrapf(err, "检查股票标签关联失败: %s", stockCode)
		}
		if exists {
			g.Log().Warning(ctx, "股票已关联该标签，跳过", "stock_code", stockCode, "tag_id", req.TagId)
			continue
		}

		stockTag := &entity.StockTag{
			StockCode:  stockCode,
			TagId:      req.TagId,
			Weight:     req.Weight,
			AssignedAt: gtime.Now(),
			AssignedBy: req.AssignedBy,
		}
		stockTags = append(stockTags, stockTag)
	}

	if len(stockTags) == 0 {
		return gerror.New("没有有效的股票需要分配标签")
	}

	// 批量插入
	err = dao.StockTag.BatchInsert(ctx, stockTags)
	if err != nil {
		return gerror.Wrap(err, "批量分配标签失败")
	}

	g.Log().Info(ctx, "批量分配标签成功", "tag_id", req.TagId, "count", len(stockTags))
	return nil
}

// RemoveTag 移除股票标签
func (s *TagService) RemoveTag(ctx context.Context, stockCode string, tagId int) error {
	// 检查关联是否存在
	exists, err := dao.StockTag.IsRelationExists(ctx, stockCode, tagId)
	if err != nil {
		return gerror.Wrap(err, "检查股票标签关联失败")
	}
	if !exists {
		return gerror.New("股票标签关联不存在")
	}

	// 删除关联
	err = dao.StockTag.DeleteByStockAndTag(ctx, stockCode, tagId)
	if err != nil {
		return gerror.Wrap(err, "移除股票标签失败")
	}

	g.Log().Info(ctx, "移除股票标签成功", "stock_code", stockCode, "tag_id", tagId)
	return nil
}

// GetStockTags 获取股票的标签列表
func (s *TagService) GetStockTags(ctx context.Context, stockCode string) ([]interface{}, error) {
	tagsMap, err := dao.StockTag.GetTagsByStock(ctx, stockCode)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票标签失败")
	}
	
	// 将 []map[string]interface{} 转换为 []interface{}
	tags := make([]interface{}, len(tagsMap))
	for i, tag := range tagsMap {
		tags[i] = tag
	}
	return tags, nil
}

// GetTagStocks 获取标签的股票列表
func (s *TagService) GetTagStocks(ctx context.Context, tagId, page, limit int) ([]interface{}, int, error) {
	// 设置默认值
	if page == 0 {
		page = 1
	}
	if limit == 0 {
		limit = 20
	}

	stocksMap, err := dao.StockTag.GetStocksByTag(ctx, tagId, page, limit)
	if err != nil {
		return nil, 0, gerror.Wrap(err, "获取标签股票失败")
	}

	total, err := dao.StockTag.GetCountByTagId(ctx, tagId)
	if err != nil {
		return nil, 0, gerror.Wrap(err, "获取标签股票总数失败")
	}

	// 将 []map[string]interface{} 转换为 []interface{}
	stocks := make([]interface{}, len(stocksMap))
	for i, stock := range stocksMap {
		stocks[i] = stock
	}

	return stocks, total, nil
}

// buildTagTree 递归构建标签树
func (s *TagService) buildTagTree(ctx context.Context, parentId int) ([]*TagTreeNode, error) {
	childTags, err := dao.Tag.GetChildTags(ctx, parentId)
	if err != nil {
		return nil, err
	}

	var children []*TagTreeNode
	for _, childTag := range childTags {
		node := &TagTreeNode{Tag: childTag}
		// 递归获取子标签
		grandChildren, err := s.buildTagTree(ctx, childTag.Id)
		if err != nil {
			g.Log().Warning(ctx, "构建子标签树失败", "tag_id", childTag.Id, "error", err)
		} else {
			node.Children = grandChildren
		}
		children = append(children, node)
	}

	return children, nil
}